import { useMemo, useState } from 'react';

import { useControllableValue, useRequest } from 'ahooks';
import { Col, Empty, Modal, Row, Segmented, Select, SelectProps, Tag } from 'antd';
import { DataNode } from 'antd/lib/tree';
import cs from 'classnames';
import { groupBy, keyBy } from 'lodash-es';

import colors from '@/config/color';
import { TargetType, TimeSort } from '@/enum';
import { orgDeptInfoTreeList } from '@/services/base/bumenguanlibumenxiangguanjiekou';
import { rolePage } from '@/services/base/jiaoseguanlijiaosexiangguanjiekou';

import Avatar from './avatar';
import DeptPanel from './dept-panel';
import styles from './index.module.scss';
import RolePanel from './role-panel';
import UserPanel from './user-panel';

export type Assignee = {
  id: number | string;
  name: string;
  type: TargetType;
  fullName?: string;
};

export type DeptDataNode = DataNode &
  Assignee & {
    value: number;
    data: BASE.OrgDeptInfoVo;
    children?: DeptDataNode[];
  };

export type RoleDataNode = DataNode &
  Assignee & {
    value: number;
    data: BASE.Role;
  };

export type BaseUserSelectProps = Omit<SelectProps, 'value' | 'onChange'> & {
  /** 选择类型 */
  selectTypeList?: TargetType[];
};

export type UserSelectProps =
  | (BaseUserSelectProps & {
      // 单选
      value?: Assignee;
      onChange?: (value: Assignee) => void;
    })
  // 多选
  | (BaseUserSelectProps & {
      mode: 'multiple';
      value?: Assignee[];
      onChange?: (value: Assignee[]) => void;
    })
  // 多选
  | (BaseUserSelectProps & {
      mode: 'tags';
      value?: Assignee[];
      onChange?: (value: Assignee[]) => void;
    });

const UserSelect = ({
  mode,
  selectTypeList = [TargetType.部门, TargetType.角色, TargetType.用户],
  className,
  ...rest
}: UserSelectProps) => {
  // 是否多选
  const isMultiple = mode === 'multiple' || mode === 'tags';
  const [open, setOpen] = useState(false);
  const [value, setValue] = useControllableValue<UserSelectProps['value']>(rest);
  const [modalValue, setModalValue] = useControllableValue<UserSelectProps['value']>();
  const [selectType, setSelectType] = useState(TargetType.用户);

  // 部门树
  const deptTree = useRequest(async () => {
    const res = await orgDeptInfoTreeList();

    const formatDeptData = (data: BASE.OrgDeptInfoVo[]): DeptDataNode[] => {
      const result: DeptDataNode[] = [];

      data.forEach((item) => {
        const node: DeptDataNode = {
          title: item.deptName,
          name: item.deptName!,
          type: TargetType.部门,
          id: item.id!,
          key: item.id!,
          value: item.id!,
          data: item,
          children: []
        };

        if (item.child && item.child.length > 0) {
          node.children = formatDeptData(item.child);
        }

        result.push(node);
      });

      return result;
    };

    return formatDeptData(res.data || []);
  });
  // 角色列表
  const roleList = useRequest(async () => {
    const res =
      (
        await rolePage({
          page: 1,
          size: 9999,
          timeSort: TimeSort.倒序
        })
      ).data?.records || [];

    return res.map<RoleDataNode>((item) => {
      return {
        title: item.roleName,
        name: item.roleName,
        id: item.id,
        key: item.id,
        type: TargetType.角色,
        value: item.id,
        data: item
      };
    });
  });
  const valueDict = useMemo(() => {
    const res = [] as Assignee[];

    if (Array.isArray(value)) {
      res.push(...value);
    } else if (value) {
      res.push(value);
    }

    return keyBy(res, 'id');
  }, [value]);

  const modalValueByType = useMemo(() => {
    if (Array.isArray(modalValue)) {
      return groupBy(modalValue, 'type');
    }

    return keyBy(modalValue ? [modalValue] : [], 'type');
  }, [modalValue]);

  const onClick: SelectProps['onClick'] = (e) => {
    setOpen(true);
    setModalValue(Array.isArray(value) ? value?.slice(0) : undefined);
  };

  const onChange: SelectProps['onChange'] = (e) => {
    if (Array.isArray(e)) {
      setValue(e.map((v) => valueDict[v]));
    }
  };

  const onCancel = () => {
    setOpen(false);
  };

  const onOk = () => {
    setOpen(false);
    if (isMultiple) {
      setValue((modalValue as Assignee[])?.slice(0));
    } else {
      setValue(modalValue);
    }
  };

  const onSelected = (item: Assignee) => {
    setModalValue((prev) => {
      if (isMultiple) {
        if ((prev as Assignee[])?.some((v) => v.id === item.id)) {
          return (prev as Assignee[])!.filter((v) => v.id !== item.id);
        } else {
          return [...((prev as Assignee[]) || []), item];
        }
      } else {
        return (prev as Assignee | undefined)?.id === item.id ? undefined : item;
      }
    });
  };

  const onModalValueChange = (type: TargetType, items: Assignee | Assignee[]) => {
    setModalValue((prev) => {
      if (isMultiple) {
        const group = groupBy((prev as Assignee[]) || [], 'type');
        group[type] = items as Assignee[];
        return Object.values(group).flat();
      } else {
        return items as Assignee;
      }
    });
  };

  const listModalValue = useMemo(() => {
    if (isMultiple) {
      return (modalValue as Assignee[]) || [];
    }

    return modalValue ? [modalValue as Assignee] : [];
  }, [isMultiple, modalValue]);

  return (
    <>
      <Select
        className={cs(styles['user-select'], className)}
        open={false}
        onClick={onClick}
        allowClear
        {...rest}
        mode={mode}
        value={Array.isArray(value) ? value.map((v) => v.id as string) : value?.id}
        onChange={onChange}
        options={
          isMultiple
            ? undefined
            : value
              ? [
                  {
                    value: (value as Assignee).id,
                    label: (
                      <Tag
                        color={colors[((value as Assignee).id as number) % colors.length]}
                        closable
                        onClose={onChange.bind(null, undefined)}
                      >
                        {(value as Assignee).name}
                      </Tag>
                    )
                  }
                ]
              : []
        }
        tagRender={(props) => {
          const color = colors[props.value % colors.length];
          return (
            <Tag color={color} closable onClose={props.onClose}>
              {valueDict[props.value]?.fullName}
            </Tag>
          );
        }}
      />

      <Modal
        open={open}
        title="选择用户"
        // footer={null}
        onCancel={onCancel}
        onOk={onOk}
        width={900}
      >
        <Row>
          <Col span={16}>
            {selectTypeList.length > 1 && (
              <Segmented
                value={selectType}
                onChange={setSelectType}
                options={[
                  { label: '选人', value: TargetType.用户 },
                  { label: '选角色', value: TargetType.角色 },
                  { label: '选部门', value: TargetType.部门 }
                ]}
                block
              />
            )}

            {selectTypeList.includes(TargetType.用户) && selectType === TargetType.用户 && (
              <UserPanel
                mode={mode}
                value={modalValueByType[TargetType.用户]}
                onChange={onModalValueChange.bind(null, TargetType.用户)}
                deptTree={deptTree.data}
                roleList={roleList.data}
              />
            )}
            {selectTypeList.includes(TargetType.角色) && selectType === TargetType.角色 && (
              <RolePanel
                mode={mode}
                value={modalValueByType[TargetType.角色]}
                onChange={onModalValueChange.bind(null, TargetType.角色)}
                roleList={roleList.data}
              />
            )}
            {selectTypeList.includes(TargetType.部门) && selectType === TargetType.部门 && (
              <DeptPanel
                mode={mode}
                value={modalValueByType[TargetType.部门]}
                onChange={onModalValueChange.bind(null, TargetType.部门)}
                deptList={deptTree.data}
              />
            )}
          </Col>
          <Col span={8}>
            {listModalValue.length ? (
              listModalValue.map((user) => {
                return (
                  <div
                    key={user.id}
                    className={styles['selected-item']}
                    onClick={onSelected.bind(null, user)}
                  >
                    <Avatar>{user?.fullName}</Avatar>
                    {user?.fullName}
                  </div>
                );
              })
            ) : (
              <Empty description="请选择用户" />
            )}
          </Col>
        </Row>
      </Modal>
    </>
  );
};

export default UserSelect;
